﻿///-----------------------------------------------------------------------
/// <copyright file="PeriodsViewModel.cs" company="FactSet Research Systems, Inc.">
///     Copyright © FactSet Research Systems, Inc.  All rights reserved 2012.
/// </copyright>
/// <author>Jonathan K. Barez</author>
///-----------------------------------------------------------------------

using System.Windows.Controls;

namespace HousholdISv2.ViewModel.Transaction
{
    using System;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Windows.Input;
    using Core;
    using DataRepository;
    using MVVMCore;
    using MVVMCore.Commanding;
    using MVVMCore.ViewModel;
    using MVVMCore.ViewModel.Details;

    public class PeriodsViewModel : ViewModelBase, IHasItemCollection
    {
        #region Fields

        private bool mustUpdateDetails = true;

        #endregion Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="PeriodsViewModel"/> class.
        /// </summary>
        public PeriodsViewModel()
        {
        }

        #endregion Constructors

        #region Events

        #endregion Events

        #region Properties

        public string DisplayName
        {
            get { return "Periods"; }
        }

        public Period ActivePeriod
        {
            get { return GetValue(() => this.ActivePeriod); }
            set { SetValue(() => this.ActivePeriod, value); }
        }

        public bool IsSelected
        {
            get { return GetValue(() => IsSelected); }
            set { SetValue(() => IsSelected, value); }
        }

        public bool IsInSelectionMode
        {
            get
            {
                return GetValue(() => this.IsInSelectionMode, true) &&
                       this.Details.OfType<IHasItemCollection>().All(vm => vm.IsInSelectionMode);
            }
            set { SetValue(() => this.IsInSelectionMode, value); }
        }

        public DatePickerViewModel Month
        {
            get { return GetValue(() => this.Month) ?? this.InitializeMonth(); }
            set { SetValue(() => this.Month, value); }
        }

        public RadioCollectionViewModel<int> Period
        {
            get { return GetValue(() => this.Period) ?? this.InitializePeriod(); }
            set { SetValue(() => this.Period, value); }
        }

        public ObservableCollection<ViewModelBase> Details
        {
            get { return GetValue(() => this.Details) ?? this.InitializeDetails(); }
            set { SetValue(() => this.Details, value); }
        }

        public ICommand PreviousCommand
        {
            get { return GetValue(() => this.PreviousCommand) ?? this.InitializeCommands(() => this.PreviousCommand); }
            set { SetValue(() => this.PreviousCommand, value); }
        }

        public ICommand NextCommand
        {
            get { return GetValue(() => this.NextCommand) ?? this.InitializeCommands(() => this.NextCommand); }
            set { SetValue(() => this.NextCommand, value); }
        }

        #endregion Properties

        #region Methods

        public void SetPeriod(DateTime startDate)
        {
            if (startDate.Day == 1)
            {
                if (!this.Period.First().IsChecked)
                {
                    this.mustUpdateDetails = false;
                    this.Period.First().IsChecked = true;
                }
            }
            else
            {
                if (!this.Period.Last().IsChecked)
                {
                    this.mustUpdateDetails = false;
                    this.Period.Last().IsChecked = true;
                }
            }

            if (!startDate.Equals(startDate))
            {
                this.Month.Value = startDate;
            }
            else
            {
                this.mustUpdateDetails = true;
                this.UpdateDetails();
            }
        }

        private DatePickerViewModel InitializeMonth()
        {
            var dpvm =
                new DatePickerViewModel
                    {
                        Caption = "Month:",
                        Value = DateTime.Now,
                        IsMonthYear = true,
                        DateFormat = "MMM, yyyy",
                        IsReadOnly = false
                    };
            dpvm.ValueChanged +=
                (sender, e) => this.UpdateDetails();
            return this.Month = dpvm;
        }

        private RadioCollectionViewModel<int> InitializePeriod()
        {
            var rcvm =
                new RadioCollectionViewModel<int>("Period:")
                    {
                        ItemSpacing = 5,
                        Orientation = Orientation.Horizontal
                    };
            rcvm.Add(1, "[Start - 15]");
            rcvm.Add(16, "[16 - End]");
            rcvm.SelectionChanged +=
                (sender, e) =>
                    {
                        if(this.IsInSelectionMode)
                        {
                            this.UpdateDetails();
                        }
                    };
            if (DateTime.Now.Day > 15)
            {
                rcvm.Last().IsChecked = true;
            }
            else
            {
                rcvm.First().IsChecked = true;
            }
            return this.Period = rcvm;
        }

        private ObservableCollection<ViewModelBase> InitializeDetails()
        {
            var cvm =
                new ObservableCollection<ViewModelBase>
                    {
                        new PeriodsAllocationViewModel(this),
                        new PeriodsBudgetSource(this),
                        new PeriodsLiquidation(this)
                    };
            return this.Details = cvm;
        }

        private void UpdateDetails()
        {
            if (this.mustUpdateDetails)
            {
                this.IsInSelectionMode = false;
                var start = new DateTime(this.Month.DateValue.Year, this.Month.DateValue.Month, this.Period.SelectedData);
                var end = new DateTime(start.Year, start.Month, 1).AddMonths(1).AddDays(-1);
                if (this.Period.SelectedData == 1)
                {
                    end = new DateTime(start.Year, start.Month, 15);
                }

                using (var dc = Context.GetContextInstance())
                {
                    this.ActivePeriod = (from p in dc.Periods
                                         where p.Start == start && p.End == end
                                         select p).SingleOrDefault() ?? new Period { Start = start, End = end };
                    this.Details.OfType<IPeriodTransaction>().ForEach(item => item.Load(this.ActivePeriod));
                }

                CommandManager.InvalidateRequerySuggested();
                this.IsInSelectionMode = true;
            }

            this.mustUpdateDetails = true;
        }

        private ICommand InitializeCommands(Expression<Func<ICommand>> command)
        {
            this.PreviousCommand = new RelayCommand(param => this.PreviousPeriod());
            this.NextCommand = new RelayCommand(param => this.NextPeriod());
            return GetValue(command);
        }

        private void SetPeriod(DateTime month,int startDay)
        {
            this.SetPeriod(new DateTime(month.Year, month.Month, startDay));
        }

        private void PreviousPeriod()
        {
            var prev = this.Period.Items.IndexOf(this.Period.SelectedItem) - 1;
            if (prev >= 0)
            {
                this.SetPeriod(this.Month.DateValue, this.Period.Items[prev].Data);
                return;
            }

            this.SetPeriod(this.Month.DateValue.AddMonths(-1), this.Period.Last().Data);
        }

        private void NextPeriod()
        {
            var next = this.Period.Items.IndexOf(this.Period.SelectedItem) + 1;
            if (next < this.Period.Items.Count)
            {
                this.SetPeriod(this.Month.DateValue, this.Period.Items[next].Data);
                return;
            }

            this.SetPeriod(this.Month.DateValue.AddMonths(1), this.Period.First().Data);
        }

        #endregion Methods
    }
}
